<?php


namespace app\service\alone\SSH;


use app\service\alone\BaseService;

class SSHService extends BaseService
{
    /** @var $connect resource ssh2连接资源 */
    private $connect;

    /** @var $sftp resource sftp连接资源 */
    private $sftp;

    protected function init()
    {
        // 建立ssh2连接
        $this->connect = ssh2_connect($this->data['host'], $this->data['port']);

        // 密码登录验证
        if (!ssh2_auth_password($this->connect, $this->data['username'], $this->data['password'])) throw new \Exception('登录失败', 500);

        // 建立sftp连接
        $this->sftp = ssh2_sftp($this->connect);
    }

    /**
     * 获取远程资源文件路径
     *
     * @param string $remotePath
     * @return string
     */
    private function getRemoteResource(string $remotePath): string
    {
        return $resource = "ssh2.sftp://" . intval($this->sftp) . $remotePath;
    }

    /**
     * 文件信息
     *
     * @param string $remotePath
     * @return array
     */
    public function fileInfo(string $remotePath): array
    {
        return ssh2_sftp_stat($this->sftp, $remotePath);
    }

    /**
     * 检查目录或文件是否存在
     *
     * @param string $remotePath
     * @return bool
     */
    public function has(string $remotePath): bool
    {
        return file_exists($this->getRemoteResource($remotePath));
    }

    /**
     * 上传文件
     *
     * @param string|resource $local 本地文件路径或文件流
     * @param string $remotePath 远程路径
     * @return bool
     */
    public function upload($local, string $remotePath): bool
    {
        // 打开文件句柄，使用进制流
        $file = [
            'remote' => fopen($this->getRemoteResource($remotePath), 'wb'),
            'local' => fopen($local, 'rb'),
        ];

        // 远程文件内容写入本地文件
        while (!feof($file['local'])) {
            fwrite($file['remote'], fread($file['local'], 2048));
        }

        // 写入完成关闭句柄
        fclose($file['local']);
        fclose($file['remote']);

        return true;
    }

    /**
     * 下载文件
     *
     * @param string $remotePath 远程路径
     * @param string $localPath 本地路径
     * @return bool
     */
    public function download(string $remotePath, string $localPath): bool
    {
        // 打开文件句柄，使用进制流
        $file = [
            'remote' => fopen($this->getRemoteResource($remotePath), 'rb'),
            'local' => fopen($localPath, 'wb'),
        ];

        // 远程文件内容写入本地文件
        while (!feof($file['remote'])) {
            fwrite($file['local'], fread($file['remote'], 2048));
        }

        // 写入完成关闭句柄
        fclose($file['remote']);
        fclose($file['local']);

        return true;
    }

    /**
     * 重命名文件
     *
     * @param string $oldRemotePath
     * @param string $newRemotePath
     * @return bool
     */
    public function rename(string $oldRemotePath, string $newRemotePath): bool
    {
        return !ssh2_sftp_rename($this->sftp, $oldRemotePath, $newRemotePath);
    }

    /**
     * 删除文件或空目录
     *
     * @param string $remotePath
     * @return bool
     */
    public function remove(string $remotePath): bool
    {
        // 删除目录或文件
        return is_dir($this->getRemoteResource($remotePath)) ? ssh2_sftp_rmdir($this->sftp, $remotePath) : ssh2_sftp_unlink($this->sftp, $remotePath);
    }

    /**
     * 断开 sftp 连接
     */
    public function disconnect(): void
    {
        try {
            @ssh2_disconnect($this->sftp);
        } catch (\Exception $exception) {
        }
    }
}